home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Light ROM 1
/
LIGHT-ROM 1 (Amiga Library Services)(1994).iso
/
ffdisks
/
d939.lha
/
ExtraCmds
/
source_etc.lha
/
src
/
SCD.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-22
|
17KB
|
653 lines
/* --------------------------------- -------
* |\ | | | | | |.| | \| |/ /|\ |||||||
* | | | |/ | |\ |/ |/| |\ |/ | ? ---+--- =<
* | | | | | | | | | | | \qqqqqqqqq/
* --------------------------------- ~~~~~~~~~~~~~~~~
* SCD - Smart CD
* Copyright (C) 1993 Torsten Poulin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The author can be contacted by s-mail at
* Torsten Poulin
* Banebrinken 99, 2, 77
* DK-2400 Copenhagen NV
* DENMARK
*
* $Id: SCD.c,v 37.4 93/04/28 15:11:53 Torsten Exp $
* $Log: SCD.c,v $
* Revision 37.4 93/04/28 15:11:53 Torsten
* Memory leak plugged.
*
* Revision 37.3 93/04/14 19:01:02 Torsten
* Allows SCDCOMMAND to be an empty string (implicit CD).
* Adjusted the size of the ListView gadget to avoid having its
* label overlap the other gadgets on a lores screen.
*
* Revision 37.2 93/04/14 10:58:16 Torsten
* Default place to look for table changed to ENV:SCD/Table
* to comply with the `User Interface Style Guide'.
* If the local or global environment variable SCDCOMMAND is
* set, SCD will queue its value (with ACTION_QUEUE) instead
* of using CurrentDir() and SetCurrentDirName() to circumvent
* a problem with WShell.
*
* Revision 37.1 93/04/12 23:18:42 Torsten
* Initial revision
*
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/lists.h>
#include <exec/nodes.h>
#include <dos/dos.h>
#include <dos/dosasl.h>
#include <dos/var.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <rexx/rexxio.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/utility_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#ifdef __SASC
#include <pragmas/dos_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/gadtools_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#endif
#include <string.h>
#include "tastlib.h"
#include "scd_rev.h"
#define PROGNAME "SCD"
#define TABNAME "SCDTABLE"
#define DEFNAME "ENV:SCD/Table"
#define CDNAME "SCDCOMMAND"
#define COPYRIGHT "Copyright © 1993 Torsten Poulin"
#define TEMPLATE "DIR/A"
#define OPT_DIR 0
typedef struct {
struct DosLibrary *DOSBase;
struct Library *UtilityBase;
struct Library *GadToolsBase;
struct Library *IntuitionBase;
struct Library *GfxBase;
struct FileInfoBlock fib;
struct List *list;
UBYTE buf[MAXNAMELEN+1];
UBYTE pattern[(MAXNAMELEN+1)*2];
} Global;
typedef struct {
struct Node nn_Node;
UBYTE nn_filename[MAXNAMELEN+1];
} NameNode;
LONG initlist(Global *global);
VOID freelist(Global *global);
LONG insert(UBYTE *filename, Global *global);
LONG SCD(UBYTE *, Global *);
LONG namereq(LONG *, Global *);
VOID handleevents(struct Window *, LONG *, struct Gadget *g[], Global *);
LONG changedir(LONG, Global *);
LONG queuecommand(UBYTE *cmd, UBYTE *arg, Global *);
struct TextAttr Topaz80 = { "topaz.font", 8, 0, 0 };
char const versionID[] = VERSTAG;
char const copyright[] = "$COPYRIGHT:" COPYRIGHT "$";
LONG entrypoint(VOID)
{
struct DosLibrary *DOSBase;
struct RDArgs *args;
Global *global;
LONG arg[1];
LONG rc = RETURN_OK;
if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
return RETURN_FAIL;
if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
{
PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
rc = RETURN_FAIL;
}
else
{
global->DOSBase = DOSBase;
if (!(global->UtilityBase = OpenLibrary("utility.library", 37L)))
rc = RETURN_FAIL;
else
{
if (!(global->IntuitionBase = OpenLibrary("intuition.library", 37L)))
rc = RETURN_FAIL;
else
{
if (!(global->GadToolsBase = OpenLibrary("gadtools.library", 37L)))
rc = RETURN_FAIL;
else
{
if (!(global->GfxBase = OpenLibrary("graphics.library", 37L)))
rc = RETURN_FAIL;
else
{
arg[OPT_DIR] = 0L;
if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
{
printerror(PROGNAME, global);
rc = RETURN_ERROR;
}
else
{
rc = SCD((UBYTE *) arg[OPT_DIR], global);
FreeArgs(args);
if (rc == ERROR_BREAK)
{
PrintFault(ERROR_BREAK, NULL);
rc = RETURN_WARN;
}
else if (rc == ERROR_NO_FREE_STORE)
{
PrintFault(ERROR_NO_FREE_STORE, PROGNAME);
rc = RETURN_FAIL;
}
else if (rc != RETURN_OK)
printerror(PROGNAME, global);
}
CloseLibrary(global->GfxBase);
}
CloseLibrary(global->GadToolsBase);
}
CloseLibrary(global->IntuitionBase);
}
CloseLibrary(global->UtilityBase);
}
FreeVec(global);
}
CloseLibrary((struct Library *) DOSBase);
return rc;
}
LONG initlist(Global *global)
{
if (!(global->list = AllocVec(sizeof(struct List), MEMF_CLEAR)))
return ERROR_NO_FREE_STORE;
/* Initialize list header */
global->list->lh_Head = (struct Node *) &global->list->lh_Tail;
global->list->lh_Tail = 0;
global->list->lh_TailPred = (struct Node *) &global->list->lh_Head;
return RETURN_OK;
}
VOID freelist(Global *global)
{
NameNode *worknode;
NameNode *nextnode;
worknode = (NameNode *) (global->list->lh_Head);
while (nextnode = (NameNode *) (worknode->nn_Node.ln_Succ))
{
FreeVec(worknode);
worknode = nextnode;
}
FreeVec(global->list);
}
LONG insert(UBYTE *filename, Global *global)
{
struct Library *UtilityBase = global->UtilityBase;
NameNode *namenode;
struct Node *node;
if (!(namenode = AllocVec(sizeof(NameNode), MEMF_CLEAR)))
return ERROR_NO_FREE_STORE;
else
{
strcpy(namenode->nn_filename, filename);
namenode->nn_Node.ln_Name = namenode->nn_filename;
if (global->list->lh_TailPred == (struct Node *) global->list)
AddHead(global->list, (struct Node *) namenode);
else
{
for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ)
if (Stricmp(node->ln_Name, filename) >= 0)
break;
if (node->ln_Succ)
Insert(global->list, (struct Node *) namenode, node->ln_Pred);
else
AddTail(global->list, (struct Node *) namenode);
}
return RETURN_OK;
}
}
LONG SCD(UBYTE *dir, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
LONG number = 0;
LONG rc = RETURN_OK;
LONG len;
UBYTE *lastpart;
BPTR table;
if (ParsePatternNoCase(dir, global->pattern, strlen(dir)*2+2) < 0)
return RETURN_FAIL;
if (GetVar(TABNAME, global->buf, MAXNAMELEN, 0) < 0)
strcpy(global->buf, DEFNAME);
if (!(table = Open(global->buf, MODE_OLDFILE)))
{
PrintFault(IoErr(), global->buf);
return RETURN_FAIL;
}
if ((rc = initlist(global)) != ERROR_NO_FREE_STORE)
{
while (FGets(table, global->buf, MAXNAMELEN+1))
{
/* remove newline character */
len = strlen(global->buf);
if (len > 0 && global->buf[--len] == '\n')
global->buf[len] = '\0';
lastpart = FilePart(global->buf);
if (MatchPatternNoCase(global->pattern, lastpart))
{
number++;
rc = insert(global->buf, global);
}
}
if (!rc)
{
--number;
if (number == 0)
rc = changedir(number, global);
else if (number > 0)
{
rc = namereq(&number, global);
if (number >= 0)
rc = changedir(number, global);
}
else
{
MyPrintf(global, "Can't find %s\n", dir);
rc = RETURN_FAIL;
}
}
freelist(global);
}
Close(table);
return rc;
}
/*
* The following three functions exist because we need global
* library bases to call the amiga.lib versions and I
* don't want the bother of building the taglists.
*/
struct Gadget *MyCreateGadget(Global *global,
ULONG kind,
struct Gadget *gad,
struct NewGadget *ng,
Tag tag1, ...)
{
struct Library *GadToolsBase = global->GadToolsBase;
return CreateGadgetA(kind, gad, ng, (struct TagItem *) &tag1);
}
struct Window *MyOpenWindowTags(Global *global,
struct NewWindow *newWindow,
Tag tag1, ...)
{
struct Library *IntuitionBase = global->IntuitionBase;
return OpenWindowTagList(newWindow, (struct TagItem *) &tag1);
}
struct Screen *MyOpenScreenTags(Global *global,
struct NewScreen *newScr,
Tag tag1, ...)
{
struct Library *IntuitionBase = global->IntuitionBase;
return OpenScreenTagList(newScr, (struct TagItem *) &tag1);
}
LONG namereq(LONG *number, Global *global)
{
struct Library *IntuitionBase = global->IntuitionBase;
struct Library *GadToolsBase = global->GadToolsBase;
struct Library *GfxBase = global->GfxBase;
struct DrawInfo *drawinfo;
struct Screen *pubscreen;
struct Screen *screen;
struct Window *window;
struct Gadget *glist, *gad;
struct Gadget *gadgets[3];
struct NewGadget ng;
ULONG modeID;
APTR vi;
glist = NULL;
if (pubscreen = LockPubScreen(NULL))
{
if (drawinfo = GetScreenDrawInfo(pubscreen))
{
if ((modeID = GetVPModeID(&(pubscreen->ViewPort))) != INVALID_ID)
{
if (screen = MyOpenScreenTags(global, NULL,
SA_Pens, (ULONG) (drawinfo->dri_Pens),
SA_Depth, drawinfo->dri_Depth,
SA_Height, STDSCREENHEIGHT,
SA_Width, STDSCREENWIDTH,
SA_DisplayID, modeID,
SA_Title, VERS " - " COPYRIGHT,
SA_Font, &Topaz80,
TAG_END))
{
if (vi = GetVisualInfoA(screen, NULL))
{
gad = CreateContext(&glist);
/* ListView gadget */
ng.ng_TextAttr = &Topaz80;
ng.ng_VisualInfo = vi;
ng.ng_LeftEdge = screen->WBorLeft + 2;
ng.ng_TopEdge = screen->WBorTop + 1;
ng.ng_Width = screen->Width - (screen->WBorLeft
+ screen->WBorRight + 4);
ng.ng_Height = (screen->Height
- ng.ng_TopEdge
- (screen->Font->ta_YSize + 1)
- 30);
ng.ng_GadgetText = "_Select directory";
ng.ng_GadgetID = 0;
ng.ng_Flags = PLACETEXT_BELOW;
gadgets[0] = gad = MyCreateGadget(global,
LISTVIEW_KIND, gad, &ng,
GTLV_Labels, global->list,
GTLV_ShowSelected, NULL,
GTLV_Selected, 0,
GT_Underscore, '_',
TAG_END);
ng.ng_Height = screen->Font->ta_YSize + 4;
ng.ng_Width = 100;
ng.ng_LeftEdge += INTERWIDTH;
ng.ng_TopEdge = (screen->Height
- (screen->WBorTop+(screen->Font->ta_YSize+1))
- screen->WBorBottom
- ng.ng_Height
- INTERHEIGHT);
ng.ng_GadgetText = "Change _dir";
ng.ng_Flags = PLACETEXT_IN;
ng.ng_GadgetID = 1;
gadgets[1] = gad = MyCreateGadget(global,
BUTTON_KIND, gad, &ng,
GT_Underscore, '_',
TAG_END);
ng.ng_LeftEdge = (screen->Width
- screen->WBorLeft - screen->WBorRight - 1
- ng.ng_Width
- INTERWIDTH);
ng.ng_GadgetText = "_Cancel";
ng.ng_GadgetID = 2;
gadgets[2] = gad = MyCreateGadget(global,
BUTTON_KIND, gad, &ng,
GT_Underscore, '_',
TAG_END);
if (gad)
{
if (window = MyOpenWindowTags(global, NULL,
WA_Gadgets, glist,
WA_Width, screen->Width,
WA_Height,
(screen->Height
- (screen->WBorTop
+ (screen->Font->ta_YSize
+ 1))),
WA_RMBTrap, TRUE,
WA_SimpleRefresh, TRUE,
WA_Activate, TRUE,
WA_Backdrop, TRUE,
WA_IDCMP, IDCMP_REFRESHWINDOW
| IDCMP_VANILLAKEY
| LISTVIEWIDCMP
| BUTTONIDCMP,
WA_CustomScreen, screen,
TAG_END))
{
GT_RefreshWindow(window, NULL);
handleevents(window, number, gadgets, global);
CloseWindow(window);
}
}
FreeGadgets(glist);
FreeVisualInfo(vi);
}
CloseScreen(screen);
}
}
FreeScreenDrawInfo(pubscreen, drawinfo);
}
UnlockPubScreen(NULL, pubscreen);
}
return RETURN_OK;
}
VOID handleevents(struct Window *window,
LONG *number,
struct Gadget *gadgets[],
Global *global)
{
struct Library *GadToolsBase = global->GadToolsBase;
struct IntuiMessage *imsg;
struct Gadget *gad;
struct TagItem lvtags[3];
LONG n = 0;
BOOL done = FALSE;
lvtags[0].ti_Tag = GTLV_Selected;
lvtags[1].ti_Tag = GTLV_Top;
lvtags[2].ti_Tag = TAG_END;
lvtags[2].ti_Data = NULL;
while (!done)
{
Wait(1 << window->UserPort->mp_SigBit);
while (!done && (imsg = GT_GetIMsg(window->UserPort)))
{
switch (imsg->Class)
{
case IDCMP_GADGETUP:
gad = (struct Gadget *) imsg->IAddress;
switch (gad->GadgetID)
{
case 0: n = imsg->Code; break;
case 1: *number = n; done = TRUE; break;
case 2: *number = -1; done = TRUE; break;
}
break;
case IDCMP_VANILLAKEY:
switch (imsg->Code)
{
case 'D':
case 'd': *number = n; done = TRUE; break;
case 'C':
case 'c': *number = -1; done = TRUE; break;
case 'S':
if (--n < 0)
n = 0;
lvtags[0].ti_Data = lvtags[1].ti_Data = (UWORD) n;
GT_SetGadgetAttrsA(gadgets[0], window, NULL, lvtags);
break;
case 's':
if (++n > *number)
n = *number;
lvtags[0].ti_Data = lvtags[1].ti_Data = (UWORD) n;
GT_SetGadgetAttrsA(gadgets[0], window, NULL, lvtags);
break;
}
break;
case IDCMP_REFRESHWINDOW:
GT_BeginRefresh(window);
GT_EndRefresh(window, TRUE);
break;
}
GT_ReplyIMsg(imsg);
}
}
}
LONG changedir(LONG number, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
struct Node *node;
LONG rc = RETURN_OK;
LONG n = 0;
BPTR lock;
for (node=global->list->lh_Head; node->ln_Succ; node=node->ln_Succ, n++)
if (n == number)
break;
if (lock = Lock(node->ln_Name, SHARED_LOCK))
{
if (Examine(lock, &global->fib)
&& global->fib.fib_DirEntryType > 0
&& global->fib.fib_DirEntryType != ST_SOFTLINK)
{
if (GetVar(CDNAME, global->buf, MAXNAMELEN, 0) >= 0)
rc = queuecommand(global->buf, node->ln_Name, global);
else
{
lock = CurrentDir(lock);
SetCurrentDirName(node->ln_Name);
}
}
else
rc = RETURN_ERROR;
UnLock(lock);
}
else
rc = RETURN_ERROR;
return rc;
}
/*
* Send ACTION_QUEUE packet to the handler associated with stdin.
* The method was learned by `reverse engineering' the QUEUE command
* shipped with the ConMan 1.3 console handler.
* Information kindly provided by Kristian Nielsen (bombadil@diku.dk)
* (and ultimately Bill Hawes, author of ARexx, ConMan, and WShell :-) ).
*/
LONG queuecommand(UBYTE *cmd, UBYTE *arg, Global *global)
{
struct DosLibrary *DOSBase = global->DOSBase;
struct FileHandle *console_fh;
struct MsgPort *destport;
struct MsgPort *port;
struct Process *process;
UBYTE *line;
LONG line_len;
BPTR console_fh_bptr;
LONG rc = RETURN_OK;
/* Add 1 for space, 2 for quotes, 1 for '\n', and 1 for '\0' */
line_len = strlen(cmd) + strlen(arg) + 5;
if (!(line = AllocVec(line_len, 0L)))
return ERROR_NO_FREE_STORE;
/* Build command line */
strcpy(line, cmd);
strcat(line," \"");
strcat(line, arg);
strcat(line, "\"\n");
/* Get process and process msgport. */
process = (struct Process *) FindTask(NULL);
port = &process->pr_MsgPort;
/*
* ACTION_QUEUE works like ACTION_READ and ACTION_WRITE.
* It takes three args: The fh_Arg1 field of the file handle
* (NOT the file handle itself), the start of the data to queue, and
* the number of bytes to queue.
*
* Since we need a file handle, we cannot just call GetConsoleTask().
* The ConMan command 'queue' uses the pr_CIS field of the process
* structure. We simply use Input().
*/
console_fh_bptr = Input(); /* Could use process->pr_CIS */
if (!console_fh_bptr)
{
MyPrintf(global, "%s: Cannot queue %s\n", PROGNAME, line);
rc = RETURN_FAIL;
}
else
{
console_fh = BADDR(console_fh_bptr); /* Convert to C pointer. */
if (!console_fh->fh_Type)
{
MyPrintf(global,
"%s: Input stream not associated with handler process\n",
PROGNAME);
rc = RETURN_FAIL;
}
else
{
destport = console_fh->fh_Type;
DoPkt(destport, ACTION_QUEUE, console_fh->fh_Arg1,
(LONG) line, line_len, 0L, 0L);
}
}
FreeVec(line);
return rc;
}